package com.finapps.stopspend.serveis;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import com.finapps.stopspend.dao.CarrecsDAO;
import com.finapps.stopspend.dao.ObjectiusDAO;
import com.finapps.stopspend.entidades.Carrec;
import com.finapps.stopspend.entidades.ObjetivoEntity;
import com.finapps.stopspend.entidades.SituacioActual;
import com.finapps.stopspend.entidades.SituacioObjectiu;
import com.finapps.stopspend.entidades.SituacioObjectiu.ColorSituacio;
import com.finapps.stopspend.util.CalendarUtils;

public class CalculSituacioActualMitjanaAny  implements CalculSituacioActual{
	private CarrecsDAO carrecsDAO=new CarrecsDAO();
	private ObjectiusDAO objectiusDAO=new ObjectiusDAO();
	
	private static BigDecimal mitjaMes;
	

	private BigDecimal getEstalviPerComparar(Calendar data) {
		Calendar unAnyAbans=Calendar.getInstance();
		unAnyAbans.add(Calendar.YEAR,-1);
		
		List<Carrec> carrecs=carrecsDAO.getAllCarrecs(CalendarUtils.calendar2Data(unAnyAbans),CalendarUtils.calendar2Data(data));

		List<Carrec> carrecsDiesATenirEnCompte=new ArrayList<Carrec>();
		for(Carrec carrec:carrecs)
			if(carrec.getDataAsCalendarSenseTemps().get(Calendar.DAY_OF_MONTH)==data.get(Calendar.DAY_OF_MONTH)) {
				carrecsDiesATenirEnCompte.add(carrec);
			}
		
		return mitjanaEstalvi(carrecsDiesATenirEnCompte);
	}
	
	private BigDecimal mitjanaEstalvi(List<Carrec> carrecs) {
		int count=0;
		double total=0;
		for(Carrec c:carrecs) {
			total+=c.getEstalviMesAcumulat().doubleValue();
		}
		if(count>0)
			return new BigDecimal(total/count);
		else
			return BigDecimal.ZERO;
	}

	@Override
	public SituacioActual calcularSituacioActual(Calendar data) {
		SituacioActual sa=new SituacioActual();
		Carrec carrec=carrecsDAO.getCarrecMesProper(CalendarUtils.calendar2Data(data),CalendarUtils.calendar2Hora(data));
		sa.setEstalvi(carrec.getEstalviMesAcumulat());
		sa.setSaldo(carrec.getSaldo());
		
		double estalvimes=carrec.getEstalviMesAcumulat().doubleValue();
		double estalvimitg=getEstalviPerComparar(data).doubleValue();
		
		if(estalvimes>estalvimitg)
			sa.setColor(ColorSituacio.VERD);
		else if(estalvimes*1.1>estalvimitg)
			sa.setColor(ColorSituacio.GROC);
		else
			sa.setColor(ColorSituacio.VERMELL);
			
		List<ObjetivoEntity> objectius=objectiusDAO.getObjectius();
		calcularSituacioObjectius(objectius,sa,carrec,data);
		
		return sa;
	}

	private void calcularSituacioObjectius(List<ObjetivoEntity> objectius,SituacioActual sa,Carrec carrec,Calendar data) {
		for(ObjetivoEntity objetivo:objectius) {
			calcularSituacioObjectiu(objetivo, sa,carrec,data);
		}
	}

	private void calcularSituacioObjectiu(ObjetivoEntity objectiu,SituacioActual sa,Carrec carrec,Calendar data) {
		SituacioObjectiu so=new SituacioObjectiu();
		double minimEstalvi=400;
		
		BigDecimal estimacioFinsObjectiu=getMitjanaAAplicarPartirData(data,objectiu.getData());
		
		double saldo=carrec.getSaldo().doubleValue();

		//Simplificaci�... caldria controlar dintre del mateix mes no entrem en numeros vermells
		if(saldo-objectiu.getPrecio().doubleValue()+estimacioFinsObjectiu.doubleValue()>=minimEstalvi) {
			so.setColorSituacio(ColorSituacio.VERD);
			so.setDinersFaltenTotal(BigDecimal.ZERO);
		} else {
			double falten=minimEstalvi-(saldo-objectiu.getPrecio().doubleValue()+estimacioFinsObjectiu.doubleValue());
			if(falten/objectiu.getPrecio().doubleValue()<0.1) {
				so.setColorSituacio(ColorSituacio.GROC);
			} else if(falten/objectiu.getPrecio().doubleValue()<0.2){
				so.setColorSituacio(ColorSituacio.TARONJA);
			} else {
				so.setColorSituacio(ColorSituacio.VERMELL);
			}
		}
	}
	
	private BigDecimal getMitjanaAAplicarPartirData1Mes(Calendar data,Calendar finsData) {
		List<Carrec> carrecsInici=new ArrayList<Carrec>();
		List<Carrec> carrecsFi=new ArrayList<Carrec>();
		
		for(int i=12;i>=0;i++) {
			Calendar cdata=(Calendar)data.clone();
			Calendar cfidata=(Calendar)finsData.clone();
			cdata.add(Calendar.MONTH,-i);
			cfidata.add(Calendar.MONTH,-i);
			if(cdata.get(Calendar.DAY_OF_MONTH)!=cfidata.get(Calendar.DAY_OF_MONTH)) {
				cdata.add(Calendar.DAY_OF_MONTH,+1);
				Carrec carrec=carrecsDAO.getUltimCarrecData(CalendarUtils.calendar2Data(cdata));
				carrecsInici.add(carrec);
				carrec=carrecsDAO.getUltimCarrecData(CalendarUtils.calendar2Data(cfidata));
				carrecsFi.add(carrec);
			}
		}
		
		double acum=0;
		for(int i=0;i<carrecsInici.size();i++) {
			Carrec cinici=carrecsInici.get(i);
			Carrec cfi=carrecsFi.get(i);
			
			acum+=cfi.getSaldo().doubleValue()-cinici.getSaldo().doubleValue();
		}
		if(!carrecsInici.isEmpty())
			return new BigDecimal(acum/carrecsInici.size());
		else
			return BigDecimal.ZERO;
	}
	
	private BigDecimal getMitjanaAAplicarPartirData(Calendar data,Calendar finsData) {
		return getMitjanaAAplicarPartirDataI(data,finsData,BigDecimal.ZERO);
	}
	
	private BigDecimal getMitjanaAAplicarPartirDataI(Calendar data,Calendar finsData,BigDecimal acumuluat) {
		BigDecimal resultat;
		if(data.get(Calendar.YEAR)==finsData.get(Calendar.YEAR) 
				&& data.get(Calendar.MONTH)==finsData.get(Calendar.MONTH)) {
			resultat=getMitjanaAAplicarPartirData1Mes(data,finsData);
		} else {
			if(mitjaMes==null) {
				Calendar inimes=Calendar.getInstance();
				inimes.set(Calendar.DAY_OF_MONTH,0);
				Calendar fimes=Calendar.getInstance();
				fimes.set(Calendar.DAY_OF_MONTH,inimes.getActualMaximum(Calendar.DAY_OF_MONTH));
				
				mitjaMes=getMitjanaAAplicarPartirData1Mes(inimes,fimes);
			}	
			resultat=mitjaMes;
		}
		return acumuluat.add(resultat);
	}

}
